{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python 机器学习实战 ——代码样例\n",
    "\n",
    "# 第十九章 人工神经网络"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 卷积神经网络识别手写数字图片\n",
    "\n",
    "下面，我们用 Keras搭建一个简单的卷积神经网络，识别 Mnist 数字图片数据集。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1391f1a1898>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 将matplotlib的图表直接嵌入到Notebook之中。\n",
    "%matplotlib inline  \n",
    "\n",
    "# 导入相关的库。\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams['figure.figsize'] = (7,7)\n",
    "from keras.datasets import mnist   \n",
    "from keras.models import Sequential\n",
    "from keras.layers.core import Dense, Dropout, Activation,Flatten \n",
    "from keras.utils import np_utils\n",
    "from keras import backend as K\n",
    "from keras.layers import Convolution2D, MaxPooling2D\n",
    "\n",
    "# 设置变量。\n",
    "\n",
    "nb_classes = 10\n",
    "img_rows, img_cols = 28, 28\n",
    "\n",
    "# 下载数据集。\n",
    "\n",
    "(X_train, y_train), (X_test, y_test) = mnist.load_data()\n",
    "\n",
    "# 查看训练样本图片的样子，如下图所示。\n",
    "\n",
    "for i in range(9):\n",
    "    plt.subplot(3,3,i+1)\n",
    "    plt.imshow(X_train[i], cmap='gray', interpolation='none')\n",
    "    plt.title(\"Class {}\".format(y_train[i]))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X_train original shape (60000, 28, 28, 1)\n",
      "y_train original shape (60000,)\n",
      "Train on 60000 samples, validate on 10000 samples\n",
      "Epoch 1/15\n",
      "60000/60000 [==============================] - 180s - loss: 0.1849 - acc: 0.9451 - val_loss: 0.0605 - val_acc: 0.9811\n",
      "Epoch 2/15\n",
      "60000/60000 [==============================] - 180s - loss: 0.0513 - acc: 0.9844 - val_loss: 0.0447 - val_acc: 0.9841\n",
      "Epoch 3/15\n",
      "60000/60000 [==============================] - 181s - loss: 0.0327 - acc: 0.9892 - val_loss: 0.0358 - val_acc: 0.9887\n",
      "Epoch 4/15\n",
      "60000/60000 [==============================] - 180s - loss: 0.0220 - acc: 0.9929 - val_loss: 0.0369 - val_acc: 0.9887\n",
      "Epoch 5/15\n",
      "60000/60000 [==============================] - 177s - loss: 0.0169 - acc: 0.9946 - val_loss: 0.0417 - val_acc: 0.9878\n",
      "Epoch 6/15\n",
      "60000/60000 [==============================] - 169s - loss: 0.0117 - acc: 0.9962 - val_loss: 0.0396 - val_acc: 0.9880\n",
      "Epoch 7/15\n",
      "60000/60000 [==============================] - 173s - loss: 0.0108 - acc: 0.9964 - val_loss: 0.0332 - val_acc: 0.9900\n",
      "Epoch 8/15\n",
      "60000/60000 [==============================] - 165s - loss: 0.0069 - acc: 0.9978 - val_loss: 0.0353 - val_acc: 0.9894\n",
      "Epoch 9/15\n",
      "60000/60000 [==============================] - 169s - loss: 0.0074 - acc: 0.9977 - val_loss: 0.0472 - val_acc: 0.9870\n",
      "Epoch 10/15\n",
      "60000/60000 [==============================] - 157s - loss: 0.0061 - acc: 0.9980 - val_loss: 0.0382 - val_acc: 0.9901\n",
      "Epoch 11/15\n",
      "60000/60000 [==============================] - 169s - loss: 0.0046 - acc: 0.9984 - val_loss: 0.0401 - val_acc: 0.9901\n",
      "Epoch 12/15\n",
      "60000/60000 [==============================] - 154s - loss: 0.0059 - acc: 0.9980 - val_loss: 0.0505 - val_acc: 0.9879\n",
      "Epoch 13/15\n",
      "60000/60000 [==============================] - 150s - loss: 0.0051 - acc: 0.9983 - val_loss: 0.0452 - val_acc: 0.9900\n",
      "Epoch 14/15\n",
      "60000/60000 [==============================] - 150s - loss: 0.0052 - acc: 0.9982 - val_loss: 0.0406 - val_acc: 0.9885\n",
      "Epoch 15/15\n",
      "60000/60000 [==============================] - 158s - loss: 0.0027 - acc: 0.9991 - val_loss: 0.0504 - val_acc: 0.9882\n",
      "10000/10000 [==============================] - 10s    \n",
      "Test score: 0.0504349716733\n",
      "Test accuracy: 0.9882\n"
     ]
    }
   ],
   "source": [
    "# 数据预处理。\n",
    "\n",
    "if K.image_dim_ordering() == 'th':\n",
    "    X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)\n",
    "    X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)\n",
    "    input_shape = (1, img_rows, img_cols)\n",
    "else:\n",
    "    X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)\n",
    "    X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)\n",
    "    input_shape = (img_rows, img_cols, 1)\n",
    "\n",
    "# 将样本数据标准化到 0-1 区间。\n",
    "\n",
    "X_train = X_train.astype('float32')\n",
    "X_test = X_test.astype('float32')\n",
    "X_train /= 255\n",
    "X_test /= 255\n",
    "\n",
    "# 查看训练集的形状，每个数字都有 6 千个样本，共 6 万张图片。\n",
    "\n",
    "print(\"X_train original shape\", X_train.shape)  \n",
    "print(\"y_train original shape\", y_train.shape)  \n",
    " \n",
    "# 将标签 ( 即 Y 值 ) 处理成 binary matrix, 如下。\n",
    "\n",
    "Y_train = np_utils.to_categorical(y_train, nb_classes)\n",
    "Y_test = np_utils.to_categorical(y_test, nb_classes)  \n",
    "\n",
    "# 建立神经网络模型。\n",
    "\n",
    "model = Sequential()\n",
    "\n",
    "# 创建第一层，卷积层 ( 32 个卷积核，尺寸 3*3 )。\n",
    "\n",
    "model.add(Convolution2D(nb_filter=32, nb_row=3,nb_col=3, border_mode='valid',\n",
    "                        input_shape=input_shape))\n",
    "model.add(Activation('relu'))\n",
    "\n",
    "# 创建第二层，卷积层。\n",
    "\n",
    "model.add(Convolution2D(nb_filter=32, nb_row=3, nb_col=3)) \n",
    "model.add(Activation('relu'))\n",
    "\n",
    "# 创建第三层，池化层。\n",
    "\n",
    "model.add(MaxPooling2D(pool_size=(2,2)))\n",
    "\n",
    "# 创建第四层，全连接层。\n",
    "\n",
    "model.add(Flatten()) \n",
    "model.add(Dense(128)) \n",
    "model.add(Activation('relu')) \n",
    "\n",
    "model.add(Dense(nb_classes)) \n",
    "model.add(Activation('softmax'))\n",
    "\n",
    "# 设置损失函数和优化器。\n",
    "\n",
    "model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])\n",
    "\n",
    "# 开始训练模型。\n",
    "\n",
    "model.fit(X_train, Y_train, batch_size=128, nb_epoch=15,\n",
    "          verbose=1, validation_data=(X_test, Y_test))\n",
    "\n",
    "# 观察测试集上的准确率。\n",
    "\n",
    "score = model.evaluate(X_test, Y_test, verbose=1)\n",
    "print('Test score:', score[0])\n",
    "print('Test accuracy:', score[1])\n",
    "\n",
    "# 保存模型文件成 json 和 h5 格式，以便后续调用。\n",
    "\n",
    "model_structure = model.to_json()\n",
    "open('model_structure.json', 'w').write(model_structure)\n",
    "model.get_weights()\n",
    "weights = model.save_weights('model_weight.h5', overwrite=True)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
